﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Xml;

namespace NcoverUtility
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void WriteToFile(string filename, StringBuilder content)
        {
            using (StreamWriter outfile = new StreamWriter(filename))
            {
                outfile.Write(content.ToString());
            }
        }
        private StringBuilder GetDocumentInfo(XmlTextReader input)
        {
            StringBuilder outPut = new StringBuilder();
            outPut.AppendFormat("id,path,mid\r\n");
            while (input.Read())
            {
                if ((input.NodeType == XmlNodeType.Element) && (input.Name == "documents"))
                {
                   outPut.Append(AppendDocumentInfo(input)) ;
                }
            }
            return outPut;
        }
        private static StringBuilder AppendDocumentInfo(XmlTextReader input )
         {
             XmlDocument xdClass = new XmlDocument();
             StringBuilder outPut=new StringBuilder();
             xdClass.LoadXml(input.ReadOuterXml());
             XmlNodeList docList = xdClass.SelectNodes("documents/doc");
             foreach (XmlNode doc in docList)
             {
                 outPut.AppendFormat("{0},{1},{2}\r\n", doc.Attributes["id"].Value, doc.Attributes["url"].Value, doc.Attributes["om"].Value);
             }
             return outPut;
         }
        private StringBuilder[] GetModuleRelatedInfo(XmlTextReader input,bool symbolDetail, bool traversedSynmbolOnly)
        {
            StringBuilder outPutModule = new StringBuilder();
            StringBuilder outPutClass = new StringBuilder();
            StringBuilder outPutMethod = new StringBuilder();
            StringBuilder outPutLineDetail = new StringBuilder();
            outPutModule.AppendFormat("id,name,assembly,totalSymbol, traversedSymbol\r\n");
            outPutClass.AppendFormat("id,name,mid,totalSymbol, traversedSymbol\r\n");
            outPutMethod.AppendFormat("id,name,mid,cid,totalSymbol, traversedSymbol\r\n");
            outPutLineDetail.AppendFormat("mid,cid,meid,code,line,visits,did\r\n");
            int moduleId = 0;
            int classId = 0;
            int moduleTotalCount = 0;
            int moduleTraverseCount = 0;
            int prevModuleId = 0;
             while (input.Read())
            {
                if ((input.NodeType == XmlNodeType.Element) && (input.Name == "module"))
                {
                    if (prevModuleId != moduleId)
                    {
                        outPutModule.AppendFormat("{0},{1}\r\n", moduleTotalCount, moduleTraverseCount);
                        moduleTotalCount = 0;
                        moduleTraverseCount = 0;
                    }
                    outPutModule.AppendFormat("{0},{1},{2},", input["moduleId"], input["name"], input["assembly"]);
                    prevModuleId = moduleId;
                    moduleId = Convert.ToInt32(input["moduleId"]);
                    classId = 0;

                }
                while ((input.NodeType == XmlNodeType.Element) && (input.Name == "class"))
                {
                    outPutClass.AppendFormat("{0},{1},{2},", ++classId, input["name"], moduleId);
                    int methodId = 0;
                    int classTotalCount = 0;
                    int classTraverseCount = 0;
                    XmlDocument xdClass = new XmlDocument();
                    xdClass.LoadXml(input.ReadOuterXml());
                    XmlNodeList methodList = xdClass.SelectNodes("class/method");
                    foreach (XmlNode method in methodList)
                    {
                        ++methodId;
                        int totalCount = method.SelectNodes("seqpnt[@fl=65536]").Count;
                        int traverseCount = method.SelectNodes("seqpnt[@fl=65536][@vc>0]").Count;
                        classTotalCount += totalCount;
                        moduleTotalCount += totalCount;
                        classTraverseCount += traverseCount;
                        moduleTraverseCount += traverseCount;
                        outPutMethod.AppendFormat("{0},{1},{2},{3},{4},{5}\r\n", methodId, method.Attributes["name"].Value,moduleId, classId, totalCount, traverseCount);
                        if (symbolDetail)
                        {
                            AddLineDetail(method, ref outPutLineDetail, moduleId, classId, methodId, traversedSynmbolOnly);
                        }
                    }
                    outPutClass.AppendFormat("{0},{1}\r\n", classTotalCount,classTraverseCount);
                }

            }
            if (moduleTotalCount > 0)
            {
                outPutModule.AppendFormat("{0},{1}\r\n", moduleTotalCount, moduleTraverseCount);
            }
            return new StringBuilder[]{outPutModule,outPutClass,outPutMethod,outPutLineDetail};
        }
        private void AddLineDetail(XmlNode method, ref StringBuilder outPutLineDetail, int moduleId, int classId, int methodId, bool traversedSynmbolOnly)
        {
            string filterCriteria = "seqpnt[@fl=65536]";
            if (traversedSynmbolOnly)
            {
                filterCriteria += "[@vc>0]";
            }
            XmlNodeList symbolList = method.SelectNodes(filterCriteria);
            foreach (XmlNode symbol in symbolList)
            {
                outPutLineDetail.AppendFormat("{0},{1},{2},{3},{4},{5},{6}\r\n", moduleId, classId, methodId, symbol.Attributes["o"].Value, symbol.Attributes["l"].Value, symbol.Attributes["vc"].Value, symbol.Attributes["doc"].Value);

            }

        }
        private string GetOuputFileName(string outputDirectory, string OutputType,bool? overWrite)
        {

            String filename = OutputType + ".csv";
            DirectoryInfo directoryInfo = new DirectoryInfo(outputDirectory);
            if ((directoryInfo.GetFiles(filename).Length > 0) && (overWrite == false) )
            {
                   throw new ArgumentException("Output File Already Exists");
            }
            return (directoryInfo.FullName + "\\" + filename);


        }
        private void btnGenerate_Click(object sender, RoutedEventArgs e)
        {
            bool overwriteOutput = chkOverwrite.IsChecked ?? false;
            ValidateInput(txtNCoverFileLocation.Text, texOutputFileLocation.Text);
            GenerateReport(txtNCoverFileLocation.Text, texOutputFileLocation.Text, cmbOutputSelection.SelectionBoxItem.ToString(), overwriteOutput);
        }

        private void ValidateInput(string inputFileFullName, string outputDirectory)
        {
            FileInfo fileInfo = new FileInfo(inputFileFullName);
            if (!fileInfo.Exists)
            {
                throw new FileNotFoundException(inputFileFullName + " Does not exists");
            }
            if (String.IsNullOrEmpty(outputDirectory))
            {
                throw new ArgumentNullException("OutPutDirectory Need to be provided");
            }
            DirectoryInfo directoryInfo = new DirectoryInfo(outputDirectory);
            if (!directoryInfo.Exists)
            {
                throw new ArgumentOutOfRangeException("Valid Output Directory Need to be provided");
            }
        }

        private void GenerateReport(string inputFileFullName, string outputFileLocation, string reportType, bool overwriteOutput)
        {
            XmlTextReader input = new XmlTextReader(inputFileFullName);
            StringBuilder ouput = GetDocumentInfo(input);
            string outputFileName = GetOuputFileName(outputFileLocation, "CodeFile", overwriteOutput);
            WriteToFile(outputFileName, ouput);
            if (reportType!= "File Report")
            {
                bool traversedSymbolOnly = false;
                bool symbolDetail = false;
                if (reportType!= "File+Module Report")
                {
                    symbolDetail = true;
                }
                //  creating file and traversed symbol report
                if (reportType== "File+Module+Traversed Symbol Report")
                {
                    traversedSymbolOnly = true;
                }
                StringBuilder[] moduleInfo = GetModuleRelatedInfo(input, symbolDetail, traversedSymbolOnly);
                WriteToFile(GetOuputFileName(outputFileLocation, "module", overwriteOutput), moduleInfo[0]);
                WriteToFile(GetOuputFileName(outputFileLocation, "class", overwriteOutput), moduleInfo[1]);
                WriteToFile(GetOuputFileName(outputFileLocation, "method", overwriteOutput), moduleInfo[2]);
                if (symbolDetail)
                {
                    WriteToFile(GetOuputFileName(texOutputFileLocation.Text, "symbol", chkOverwrite.IsChecked), moduleInfo[3]);
                }

            }
        }
    }
}
